package bb.lanxing.lib.devices.bici;

import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.text.TextUtils;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.UUID;

import bb.lanxing.lib.devices.api.SmartDevice;
import bb.lanxing.lib.devices.bici.cmd.AckPacket;
import bb.lanxing.lib.devices.bici.cmd.CyclingCMD;
import bb.lanxing.lib.devices.bici.cmd.DeviceControlCMD;
import bb.lanxing.lib.devices.bici.cmd.FileTransCMD;
import bb.lanxing.lib.devices.bici.cmd.FirmwareCMD;
import bb.lanxing.lib.devices.bici.cmd.SettingCMD;
import bb.lanxing.lib.devices.bici.cmd.StatusCMD;
import bb.lanxing.lib.devices.bici.cmd.UserConnectCMD;
import bb.lanxing.lib.devices.core.ble.AbsBleDevice;
import bb.lanxing.lib.devices.core.ble.BaseBluetoothGattCallback;
import bb.lanxing.lib.devices.core.exception.TimeoutException;
import bb.lanxing.lib.devices.sprint.Commands;
import bb.lanxing.lib.devices.utils.ByteUtils;
import bb.lanxing.lib.devices.utils.CRC;

public class BICIDevice extends AbsBleDevice implements BiciCallback {
    public static final String BICI_FILE_LIST = "filelist";
    public static final String BICI_INFO = "con";
    public static final int ERROR_DEVICE_NOT_RESPONSE = 2;
    public static final int ERROR_PHONE_NOT_EXISTS = 1;
    public static final UUID BLE_SHIELD_SERVICE_NOTIFY = UUID.fromString(BiciAttributes.BLE_SHIELD_SERVICE_NOTIFY);
    public static final UUID BLE_SHIELD_SERVICE_WRITER = UUID.fromString(BiciAttributes.BLE_SHIELD_SERVICE_WRITER);
    public static final UUID BLE_SHIELD_NOTIFY = UUID.fromString(BiciAttributes.BLE_SHIELD_NOTIFY);
    public static final UUID BLE_SHIELD_WRITER = UUID.fromString(BiciAttributes.BLE_SHIELD_WRITER);
    public static final UUID BLE_PASSWORD_SERVICE = UUID.fromString(BiciAttributes.BLE_PASSWORD_SERVICE);
    public static final UUID BLE_PASSWORD_READER = UUID.fromString(BiciAttributes.BLE_PASSWORD_READER);
    public static final UUID BLE_PASSWORD_WRITER = UUID.fromString(BiciAttributes.BLE_PASSWORD_WRITER);
    private static final String BICI_ROOT_DIR = ".bici";
    private static final String BODY_TAIL = ".l";
    private static final int DEFAULT_BLE_MTU = 20;
    private static final int DEFAULT_COMMAND_ACK_TIMEOUT = 10000;
    private static final int DEFAULT_COMMAND_TIMEOUT = 30000;
    private static final int DEFAULT_SEND_TIMES = 3;
    private static final String HEAD_TAIL = ".h";
    private static final int OP_SEND_COMMAND = 16711680;
    private static final int OP_UPGRADE = 1;
    public static String TAG = "GattClient-bici";
    private final Object mLock;
    private final BiciNotifier mBiciNotifier;
    private Runnable mCloseRunnable;
    private final BiciController mController;
    private byte mErrorFlag;
    private boolean mIsSporting;
    private boolean mNotify;
    private BluetoothGattCharacteristic mPasswordReader;
    private BluetoothGattCharacteristic mPasswordWriter;
    private ByteBuffer mReceivedData;
    private BluetoothGattCharacteristic mShieldNotify;
    private BluetoothGattCharacteristic mShieldWriter;
    private int mWriteStatus;

    public BICIDevice(Context context, SmartDevice smartDevice) {
        super(smartDevice);
        this.mLock = new Object();
        init(context, smartDevice.getAddress(), new BICIGattCallback(this));
        TAG = getTag();
        SimpleBiciController simpleBiciController = new SimpleBiciController(this);
        this.mController = simpleBiciController;
        this.mBiciNotifier = simpleBiciController;
    }

    public BiciController getController() {
        return this.mController;
    }

    protected boolean onStateChanged(int i, int i2) {
        this.mBiciNotifier.notifyStateChanged(getDevice(), i, i2);
        return false;
    }

    public boolean isConnected() {
        return super.isConnected();
    }

    public void onServicesDiscovered() {
        BluetoothGattService service = this.mBluetoothGatt.getService(BLE_SHIELD_SERVICE_NOTIFY);
        BluetoothGattService service2 = this.mBluetoothGatt.getService(BLE_SHIELD_SERVICE_WRITER);
        BluetoothGattService service3 = this.mBluetoothGatt.getService(BLE_PASSWORD_SERVICE);
        if (service == null || service2 == null || service3 == null) {
            e("Failed to get services");
            _close();
            return;
        }
        this.mShieldNotify = service.getCharacteristic(BLE_SHIELD_NOTIFY);
        this.mShieldWriter = service2.getCharacteristic(BLE_SHIELD_WRITER);
        this.mPasswordReader = service3.getCharacteristic(BLE_PASSWORD_READER);
        BluetoothGattCharacteristic characteristic = service3.getCharacteristic(BLE_PASSWORD_WRITER);
        this.mPasswordWriter = characteristic;
        if (this.mShieldNotify == null || this.mShieldWriter == null || characteristic == null || this.mPasswordReader == null) {
            e("Failed to get characteristics");
            _close();
            return;
        }
        this.mBluetoothGatt.setCharacteristicNotification(this.mShieldNotify, true);
        setBiciTime();
    }

    public void handleMessage(Message message) {
        super.handleMessage(message);
        int i = message.what;
        if ((i & OP_SEND_COMMAND) != OP_SEND_COMMAND) {
            if (i == 1) {
                _upgrade((String) message.obj);
                return;
            }
            return;
        }
        int i2 = i & (-16711681);
        try {
            sendCmd((byte[]) message.obj, message.arg1, message.arg2);
            this.mBiciNotifier.notifyCmdStatus(i2, 0);
        } catch (TimeoutException e) {
            e(e);
            this.mBiciNotifier.notifyCmdStatus(i2, 1);
        }
    }

    private void _upgrade(String str) {
        File file = new File(str);
        if (!file.exists()) {
            this.mBiciNotifier.notifyCmdStatus(1, 1);
            return;
        }
        this.mBiciNotifier.notifyCmdStatus(1, 1);
        int length = (int) file.length();
        short ceil = (short) Math.ceil(length / 120.0d);
        d("sendUpgradeFirmware, filePath = " + str + ", fileSize = " + length + ", packageCount = " + ((int) ceil));
        HashMap hashMap = new HashMap();
        FirmwareCMD firmwareCMD = new FirmwareCMD();
        hashMap.put((byte) 1, file.getName());
        hashMap.put((byte) 2, length);
        hashMap.put((byte) 3, ceil);
        byte[] buildCommand = firmwareCMD.buildCommand(0, hashMap);
        try {
            this.mBiciNotifier.notifyCmdStatus(1, 2);
            sendCmd(buildCommand, 0, buildCommand.length);
            short s = (short) 1;
            FileInputStream fileInputStream = new FileInputStream(file);
            int i = 0;
            while (i < length) {
                int i2 = length - i;
                if (i2 > 120) {
                    i2 = 120;
                }
                d("size = " + i + ", index = " + ((int) s) + ", totalSize = " + length + ", totalPackage = " + ((int) ceil));
                byte[] bArr = new byte[i2];
                fileInputStream.read(bArr);
                HashMap hashMap2 = new HashMap();
                FirmwareCMD firmwareCMD2 = new FirmwareCMD();
                hashMap2.put((byte) 4, s);
                hashMap2.put((byte) 5, bArr);
                byte[] buildCommand2 = firmwareCMD2.buildCommand(0, hashMap2);
                sendCmd(buildCommand2, 0, buildCommand2.length);
                s = (short) (s + 1);
                i += i2;
                this.mBiciNotifier.notifyProgressUpdate(1, Math.min((int) ((i / length) * 100.0f), 100));
            }
            fileInputStream.close();
            this.mBiciNotifier.notifyCmdStatus(1, 3);
        } catch (TimeoutException | IOException e) {
            e(e);
            this.mBiciNotifier.notifyCmdStatus(1, 4);
        }
    }

    private boolean sendCmd(byte[] bArr, int i, int i2) throws TimeoutException {
        if (this.mBluetoothGatt == null || !isServicesDiscovered()) {
            e("Unable to send command to remote device");
            return false;
        }
        SystemClock.sleep(20L);
        d("try to send command to remote device: " + ByteUtils.printlnByteArrayToUnsignHexString(bArr));
        int i3 = i2 > 20 ? 20 : i2;
        byte[] bArr2 = new byte[i3];
        System.arraycopy(bArr, i, bArr2, 0, i3);
        this.mNotify = false;
        boolean execute = execute(Request.newWriteRequest(this.mShieldWriter, bArr2));
        if (execute) {
            if (i2 > 20) {
                return sendCmd(bArr, i + 20, i2 - 20);
            }
            d("Waiting for ack");
            this.mErrorFlag = (byte) 0;
            synchronized (this.mLock) {
                if (!this.mNotify) {
                    try {
                        this.mLock.wait(10000L);
                    } catch (InterruptedException e) {
                        e(e);
                    }
                }
                if (!this.mNotify) {
                    e("Timeout while waiting for ack");
                    throw new TimeoutException("Timeout while waiting for ack");
                }
                String format = String.format("Ack packet: error(%d)", Byte.valueOf(this.mErrorFlag));
                if (this.mErrorFlag == 0) {
                    d(format);
                    execute = true;
                } else {
                    e(format);
                    execute = false;
                }
                this.mNotify = false;
            }
        }
        if (execute) {
            d("Send successful");
        } else {
            e("Send failed");
        }
        return execute;
    }

    private void setBiciTime() {
        this.mController.sendTimeSetting(System.currentTimeMillis());
    }

    public void process(byte[] bArr) {
        int findMagic;
        if (this.mReceivedData == null) {
            this.mReceivedData = ByteBuffer.allocate(1024);
        }
        if (isAckResponse(bArr)) {
            this.mReceivedData.clear();
        }
        this.mReceivedData.put(bArr);
        int position = this.mReceivedData.position();
        byte[] bArr2 = new byte[position];
        int position2 = this.mReceivedData.position();
        this.mReceivedData.position(0);
        this.mReceivedData.get(bArr2);
        this.mReceivedData.position(position2);
        int findMagic2 = findMagic(0, bArr2);
        if (findMagic2 == -1 || findMagic2 + 8 > position) {
            return;
        }
        short s = this.mReceivedData.getShort(findMagic2 + 2);
        int i = s + 8;
        int i2 = (findMagic2 + i) - 1;
        d("data: " + ByteUtils.printlnByteArrayToUnsignHexString(bArr));
        d("buffer: " + position);
        d("contentLength: " + ((int) s));
        d("packetLength:" + i);
        d("startIndex: " + findMagic2);
        d("endIndex: " + i2);
        if (s < 0 || s > 200) {
            this.mReceivedData.clear();
        } else if (i2 < position) {
            byte[] bArr3 = new byte[i];
            System.arraycopy(bArr2, findMagic2, bArr3, 0, i);
            this.mReceivedData.clear();
            if (parsePacket(bArr3) || (findMagic = findMagic(0, bArr)) == -1) {
                return;
            }
            this.mReceivedData.clear();
            this.mReceivedData.put(bArr, findMagic, bArr.length - findMagic);
        }
    }

    public synchronized void reset() {
        ByteBuffer byteBuffer = this.mReceivedData;
        if (byteBuffer != null) {
            byteBuffer.clear();
        }
    }

    private boolean parsePacket(byte[] bArr) {
        ByteBuffer wrap = ByteBuffer.wrap(bArr);
        wrap.get();
        byte b = wrap.get();
        int i = wrap.getShort();
        short s = wrap.getShort();
        wrap.getShort();
        if ((b & 16) > 0) {
            onAckPacket(new AckPacket(bArr));
        } else {
            int position = wrap.position();
            byte[] bArr2 = new byte[i];
            wrap.get(bArr2);
            wrap.position(position);
            byte b2 = wrap.get();
            byte b3 = wrap.get();
            byte[] bArr3 = new byte[i - 2];
            wrap.get(bArr3);
            if (CRC.getCrc16(bArr2) != s || s == 0) {
                e("CRC ERROR : " + ByteUtils.printlnByteArrayToUnsignHexString(bArr2));
                return false;
            }
            parseCmd(bArr3, b2, b3);
        }
        return true;
    }

    private void parseCmd(byte[] bArr, byte b, byte b2) {
        BLECommand deviceControlCMD;
        if (b == 2) {
            deviceControlCMD = new DeviceControlCMD(bArr);
        } else if (b == 3) {
            deviceControlCMD = new UserConnectCMD(bArr);
        } else if (b == 5) {
            deviceControlCMD = new CyclingCMD(bArr);
        } else if (b == 6) {
            deviceControlCMD = new StatusCMD(bArr);
        } else if (b == 7) {
            deviceControlCMD = new SettingCMD(bArr);
        } else {
            deviceControlCMD = b != 11 ? null : new FileTransCMD(bArr);
        }
        if (deviceControlCMD != null) {
            if (b == 6 || b == 7 || b == 2 || b == 5) {
                this.mBiciNotifier.notifyPackage(b, bArr);
            }
            d(deviceControlCMD.toString());
            deviceControlCMD.setCommandId(b);
            handleCmd(deviceControlCMD);
        }
    }

    private int findMagic(int i, byte[] bArr) {
        int i2;
        int i3;
        while (bArr != null && i < bArr.length) {
            if (bArr[i] == -85 && ((i2 = i + 1) >= bArr.length || (i3 = bArr[i2] & Commands.ENTER_DFU_MODE) == 17 || i3 == 1)) {
                return i;
            }
            i++;
        }
        return -1;
    }

    private boolean isAckResponse(byte[] bArr) {
        return findMagic(0, bArr) == 0 && bArr.length == 8 && ((bArr[1] & 16) >> 4) == 1;
    }

    public void onAckPacket(AckPacket ackPacket) {
        if (ackPacket.getL1ErrFlag() != 0) {
            e("Ack packet: " + ackPacket);
        } else {
            d("Ack packet: " + ackPacket);
        }
        synchronized (this.mLock) {
            this.mErrorFlag = ackPacket.getL1ErrFlag();
            this.mNotify = true;
            this.mLock.notifyAll();
        }
    }

    private void handleCmd(BLECommand bLECommand) {
        byte commandId = bLECommand.getCommandId();
        if (commandId == 2) {
            DeviceControlCMD deviceControlCMD = (DeviceControlCMD) bLECommand;
        } else if (commandId == 3) {
            handleUserConnect((UserConnectCMD) bLECommand);
        } else if (commandId == 5) {
            byte flag = ((CyclingCMD) bLECommand).getFlag();
            boolean z = flag == 0 || flag == 1 || flag == 3;
            this.mIsSporting = z;
        } else if (commandId == 6) {
            StatusCMD statusCMD = (StatusCMD) bLECommand;
        } else if (commandId == 7) {
            SettingCMD settingCMD = (SettingCMD) bLECommand;
        } else if (commandId != 11) {
        } else {
            try {
                BiCiFileManager.getInstance().update((FileTransCMD) bLECommand, this.mBiciNotifier);
            } catch (IOException e) {
                e(e);
            }
        }
    }

    private void handleUserConnect(UserConnectCMD userConnectCMD) {
        Handler handler = getHandler();
        Runnable runnable = this.mCloseRunnable;
        if (runnable != null) {
            handler.removeCallbacks(runnable);
        }
        setBiciTime();
    }

    @Override
    public boolean send(byte[] bArr) {
        Handler handler;
        if (!isServicesDiscovered() || (handler = getHandler()) == null || bArr == null) {
            return false;
        }
        return handler.sendMessage(handler.obtainMessage((bArr.length > 8 ? bArr[8] : (byte) 0) | OP_SEND_COMMAND, 0, bArr.length, bArr));
    }

    public boolean sendSync(byte[] bArr) {
        try {
            if (isServicesDiscovered()) {
                return sendCmd(bArr, 0, bArr.length);
            }
            return false;
        } catch (TimeoutException e) {
            e(e);
            this.mBiciNotifier.notifyCmdStatus(0, 2);
            return false;
        }
    }

    @Override
    public boolean upgrade(String str) {
        if (!isServicesDiscovered() || TextUtils.isEmpty(str)) {
            this.mBiciNotifier.notifyCmdStatus(11, 1);
            return false;
        }
        Handler handler = getHandler();
        return handler.sendMessage(handler.obtainMessage(1, str));
    }

    @Override
    public boolean isSporting() {
        return isConnected() && this.mIsSporting;
    }


    public class BICIGattCallback extends BaseBluetoothGattCallback<BICIDevice> {
        public BICIGattCallback(BICIDevice bICIDevice) {
            super(bICIDevice);
        }

        @Override
        public void onCharacteristicChanged(BluetoothGatt bluetoothGatt, BluetoothGattCharacteristic bluetoothGattCharacteristic) {
            super.onCharacteristicChanged(bluetoothGatt, bluetoothGattCharacteristic);
            byte[] value = bluetoothGattCharacteristic.getValue();
            synchronized (BICIDevice.this) {
                try {
                    BICIDevice.this.process(value);
                } catch (Exception unused) {
                    if (BICIDevice.this.mReceivedData != null) {
                        BICIDevice.this.mReceivedData.clear();
                    }
                }
            }
        }
    }
}
